home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
muds
/
pennmush.000
/
pennmush-1.50-p8-linux.tar
/
pennmush
/
bsd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-04-21
|
55KB
|
2,428 lines
/* bsd.c */
#include "copyright.h"
#include <stdio.h>
#include <varargs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/errno.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <sys/param.h>
#ifdef HPUX
#include <unistd.h>
#endif
#include "config.h"
#include "db.h"
#include "interface.h"
#include "externs.h"
#include "globals.h"
#include "help.h"
#ifdef MEM_CHECK
#include "mem_check.h"
#endif
#if (CHAT_SYSTEM >= 2)
#include "chat.h"
#endif
/* AIX, BSD 4.2, and maybe some others need these defined */
#ifndef FD_ZERO
#define fd_set int
#define FD_ZERO(p) (*p = 0)
#define FD_SET(n,p) (*p |= (1<<(n)))
#define FD_CLR(n,p) (*p &= ~(1<<(n)))
#define FD_ISSET(n,p) (*p & (1<<(n)))
#endif /* defines for AIX */
extern void rusage_stats();
extern dbref speaker;
extern int errno;
extern int reserved;
int shutdown_flag = 0;
extern dbref db_top;
#ifdef LOGIN_LIMIT
static int login_number = 0;
#endif /* LOGIN_LIMIT */
static int under_limit = 1;
char cf_motd_msg[BUFFER_LEN], cf_wizmotd_msg[BUFFER_LEN],
cf_downmotd_msg[BUFFER_LEN], cf_fullmotd_msg[BUFFER_LEN];
#ifdef AT_DOING
static char poll[39];
#endif
struct text_block {
int nchars;
struct text_block *nxt;
char *start;
char *buf;
};
struct text_queue {
struct text_block *head;
struct text_block **tail;
};
struct descriptor_data {
int descriptor;
int connected;
char addr[51];
dbref player;
char *output_prefix;
char *output_suffix;
int output_size;
struct text_queue output;
struct text_queue input;
char *raw_input;
char *raw_input_at;
long connected_at;
long last_time;
int quota;
int cmds;
int hide;
#ifdef AT_DOING
char doing[40];
#endif
struct sockaddr_in address; /* added 3/6/90 SCG */
struct descriptor_data *next;
struct descriptor_data **prev;
};
typedef struct descriptor_data DESC;
#define DESC_ITER_CONN(d) \
for(d = descriptor_list;(d);d=(d)->next) \
if((d)->connected)
#define Hidden(d) ((d->hide == 1) && Can_Hide(d->player))
/* log file pointers */
FILE *connlog_fp;
FILE *checklog_fp;
FILE *wizlog_fp;
FILE *tracelog_fp;
FILE *cmdlog_fp;
static const char *connect_fail = "Either that player does not exist, or has a different password.\n";
static const char *create_fail = "Either there is already a player with that name, or that name is illegal.\n";
static const char *flushed_message = "<Output Flushed>\n";
static const char *shutdown_message = "Going down - Bye\n";
static const char *asterisk_line =
"*****************************************************************";
struct descriptor_data *descriptor_list = 0;
static int sock;
static int ndescriptors = 0;
char ccom[BUFFER_LEN];
dbref cplr;
void process_commands();
void shovechars();
void shutdownsock();
struct descriptor_data *initializesock();
void make_nonblocking();
void freeqs();
void welcome_user();
int check_connect();
void close_sockets();
const char *hostname_convert();
void dump_users();
#ifdef RWHO_SEND
#ifdef FULL_RWHO
void dump_rusers();
#endif
void rwho_update();
#endif
void set_signals();
struct descriptor_data *new_connection();
void parse_connect();
void set_userstring();
int do_command();
char *strsave();
int make_socket();
int queue_string();
int queue_write();
int process_output();
int process_input();
int bailout();
void srand();
void announce_connect();
void announce_disconnect();
const char *time_format_1();
const char *time_format_2();
#ifdef IDLE_TIMEOUT
void inactivity_check();
#endif
#ifndef BOOLEXP_DEBUGGING
void main(argc, argv)
int argc;
char **argv;
{
#ifdef AUTORESTART
FILE *id;
#endif
/* read the configuration file */
if (argc < 1) {
fprintf(stderr, "ERROR: No configuration file! Exiting.\n");
exit(2);
}
#ifndef SINGLE_LOGFILE
/* open the log files */
start_log(&connlog_fp, CONNLOG);
start_log(&checklog_fp, CHECKLOG);
start_log(&wizlog_fp, WIZLOG);
start_log(&tracelog_fp, TRACELOG);
start_log(&cmdlog_fp, CMDLOG);
#else
connlog_fp = checklog_fp = wizlog_fp = tracelog_fp = cmdlog_fp = stderr;
#endif /* SINGLE_LOGFILE */
/* this writes a file used by the restart script to check for active mush */
#ifdef AUTORESTART
id = fopen("runid", "w");
fprintf(id, "%d", getpid());
fclose(id);
#endif
srand(time(NULL));
/* save a file descriptor */
reserved = open("/dev/null", O_RDWR);
if (init_game(argv[1]) < 0) {
fprintf(stderr, "ERROR: Couldn't load %s! Exiting.\n", DEF_DB_IN);
exit(2);
}
set_signals();
#ifdef RWHO_SEND
rwhocli_setup(RWHOSERV, RWHOPASS, MUDNAME, SHORTVN);
#endif
/* go do it */
shovechars(TINYPORT);
/* someone has told us to shut down */
#ifdef ALLOW_RPAGE
rpage_shutdown(); /* do this first */
#endif /* ALLOW_RPAGE */
close_sockets();
dump_database();
#ifndef SINGLE_LOGFILE
/* close up the log files */
end_log(connlog_fp);
end_log(checklog_fp);
end_log(wizlog_fp);
end_log(tracelog_fp);
end_log(cmdlog_fp);
#endif /* SINGLE_LOGFILE */
#ifdef HAS_RUSAGE
rusage_stats();
#endif /* HAS_RUSAGE */
fprintf(stderr, "\nMUSH shutdown completed.\n");
fflush(stderr);
close(sock); /* patch moving this line here fixes
* @shutdown error */
exit(0);
}
#endif /* BOOLEXP_DEBUGGING */
void set_signals()
{
/* we don't care about SIGPIPE, we notice it in select() and write() */
signal(SIGPIPE, SIG_IGN);
/* standard termination signals */
signal(SIGINT, (void *)bailout);
signal(SIGTERM, (void *)bailout);
}
void raw_notify(player, msg)
dbref player;
const char *msg;
{
struct descriptor_data *d;
if (!msg || *msg == '\0')
return;
if (!Connected(player) && options.login_allow && under_limit)
return;
for (d = descriptor_list; d; d = d->next) {
if (d->connected && d->player == player) {
queue_string(d, msg);
queue_write(d, "\n", 1);
}
}
}
void raw_broadcast(inflags, va_alist)
object_flag_type inflags;
va_dcl
{
/* takes a flag mask, format string, and format args, and notifies
* all connected players with that flag mask of something. Players
* with _at least_ one of the bits in the flag mask are notified,
* rather than players with that _entire_ flag mask. The former
* behavior is more useful.
*/
va_list args;
char *fmt;
char tbuf1[BUFFER_LEN];
DESC *d;
va_start(args);
fmt = va_arg(args, char *);
(void) vsprintf(tbuf1, fmt, args);
DESC_ITER_CONN(d) {
if ((Flags(d->player) & inflags) || !inflags) {
queue_string(d, tbuf1);
queue_write(d, "\n", 1);
process_output(d);
}
}
}
static void toggle_broadcast(inflags, va_alist)
object_flag_type inflags;
va_dcl
{
/* like raw_broadcast but uses toggles.
*/
va_list args;
char *fmt;
char tbuf1[BUFFER_LEN];
DESC *d;
va_start(args);
fmt = va_arg(args, char *);
(void) vsprintf(tbuf1, fmt, args);
DESC_ITER_CONN(d) {
if ((Toggles(d->player) & inflags) || !inflags) {
queue_string(d, tbuf1);
queue_write(d, "\n", 1);
process_output(d);
}
}
}
struct timeval timeval_sub(now, then)
struct timeval now;
struct timeval then;
{
now.tv_sec -= then.tv_sec;
now.tv_usec -= then.tv_usec;
if (now.tv_usec < 0) {
now.tv_usec += 1000000;
now.tv_sec--;
}
return now;
}
long msec_diff(now, then)
struct timeval now;
struct timeval then;
{
return ((now.tv_sec - then.tv_sec) * 1000
+ (now.tv_usec - then.tv_usec) / 1000);
}
struct timeval msec_add(t, x)
struct timeval t;
int x;
{
t.tv_sec += x / 1000;
t.tv_usec += (x % 1000) * 1000;
if (t.tv_usec >= 1000000) {
t.tv_sec += t.tv_usec / 1000000;
t.tv_usec = t.tv_usec % 1000000;
}
return t;
}
struct timeval update_quotas(last, current)
struct timeval last;
struct timeval current;
{
int nslices;
struct descriptor_data *d;
nslices = (int) msec_diff(current, last) / COMMAND_TIME_MSEC;
if (nslices > 0) {
for (d = descriptor_list; d; d = d->next) {
d->quota += COMMANDS_PER_TIME * nslices;
if (d->quota > COMMAND_BURST_SIZE)
d->quota = COMMAND_BURST_SIZE;
}
}
return msec_add(last, nslices * COMMAND_TIME_MSEC);
}
void shovechars(port)
int port;
{
/* this is the main game loop */
fd_set input_set, output_set;
time_t now;
struct timeval last_slice, current_time;
struct timeval next_slice;
struct timeval timeout, slice_timeout;
int maxd, found;
struct descriptor_data *d, *dnext;
struct descriptor_data *newd;
int avail_descriptors;
extern void dispatch();
sock = make_socket(port);
maxd = sock + 1;
gettimeofday(&last_slice, (struct timezone *) 0);
#ifdef HPUX
avail_descriptors = sysconf(_SC_OPEN_MAX);
#else
avail_descriptors = getdtablesize() - 4;
#endif
/* done. print message to the log */
fprintf(stderr, "RESTART FINISHED.\n");
fflush(stderr);
while (shutdown_flag == 0) {
gettimeofday(¤t_time, (struct timezone *) 0);
last_slice = update_quotas(last_slice, current_time);
process_commands();
if (shutdown_flag)
break;
/* test for events */
dispatch();
#ifdef ALLOW_RPAGE
/* anything received on our datagram remote page? */
recv_rpage();
#endif /* ALLOW_RPAGE */
/* any queued robot commands waiting? */
timeout.tv_sec = test_top() ? 0 : 1000;
timeout.tv_usec = 0;
next_slice = msec_add(last_slice, COMMAND_TIME_MSEC);
slice_timeout = timeval_sub(next_slice, current_time);
FD_ZERO(&input_set);
FD_ZERO(&output_set);
if (ndescriptors < avail_descriptors)
FD_SET(sock, &input_set);
for (d = descriptor_list; d; d = d->next) {
if (d->input.head)
timeout = slice_timeout;
else
FD_SET(d->descriptor, &input_set);
if (d->output.head)
FD_SET(d->descriptor, &output_set);
}
if ((found = select(maxd, &input_set, &output_set,
(fd_set *) 0, &timeout)) < 0) {
if (errno != EINTR) {
perror("select");
return;
}
} else {
/* if !found then time for robot commands */
if (!found) {
do_top();
do_top();
do_top();
continue;
}
now = time((time_t *) 0);
if (FD_ISSET(sock, &input_set)) {
if (!(newd = new_connection(sock))) {
if (errno
&& errno != EINTR
&& errno != EMFILE
&& errno != ENFILE) {
perror("new_connection");
return;
}
} else {
if (newd->descriptor >= maxd)
maxd = newd->descriptor + 1;
}
}
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
if (FD_ISSET(d->descriptor, &input_set)) {
d->last_time = now;
if (!process_input(d)) {
shutdownsock(d);
continue;
}
}
if (FD_ISSET(d->descriptor, &output_set)) {
if (!process_output(d)) {
shutdownsock(d);
}
}
}
}
}
}
struct descriptor_data *new_connection(oldsock)
int oldsock;
{
int newsock;
struct sockaddr_in addr;
int addr_len;
char tbuf1[BUFFER_LEN];
addr_len = sizeof(addr);
newsock = accept(oldsock, (struct sockaddr *) &addr, &addr_len);
if (newsock < 0) {
return 0;
#ifdef LOCKOUT
} else if (forbidden_site(1, hostname_convert(addr.sin_addr))) {
do_log(LT_CONN, 0, 0, "[%d/%s] Refused connection (remote port %d)",
newsock, hostname_convert(addr.sin_addr), ntohs(addr.sin_port));
shutdown(newsock, 2);
close(newsock);
errno = 0;
return 0;
#endif /* LOCKOUT */
} else {
strcpy(tbuf1, (char *)hostname_convert(addr.sin_addr));
do_log(LT_CONN, 0, 0, "[%d/%s] Connection opened.", newsock, tbuf1);
return initializesock(newsock, &addr, tbuf1);
}
}
void clearstrings(d)
struct descriptor_data *d;
{
if (d->output_prefix) {
free((void *) d->output_prefix);
#ifdef MEM_CHECK
del_check("userstring");
#endif
d->output_prefix = 0;
}
if (d->output_suffix) {
free((void *)d->output_suffix);
#ifdef MEM_CHECK
del_check("userstring");
#endif
d->output_suffix = 0;
}
}
void fcache_dump(d, fp)
DESC *d;
FBLOCK *fp;
{
while (fp != NULL) {
queue_write(d, fp->data, fp->hdr.nchars);
fp = fp->hdr.nxt;
}
}
int fcache_read(cp, filename)
FBLOCK **cp;
char *filename;
{
int n, nmax, fd, tchars;
char *bufp;
FBLOCK *fp, *tfp;
/* Free prior buffer chain */
fp = *cp;
while (fp != NULL) {
tfp = fp->hdr.nxt;
free(fp);
fp = tfp;
}
*cp = NULL;
/* Read the text file into a new chain */
close(reserved);
if ((fd = open(filename, O_RDONLY, 0)) == -1) {
do_log(LT_ERR, 0, 0, "couldn't open cached text file '%s'", filename);
return -1;
}
fp = (FBLOCK *)malloc(sizeof(char) * 256);
fp->hdr.nxt = NULL;
fp->hdr.nchars = 0;
*cp = fp;
tfp = NULL;
tchars = 0;
/* Read in the first chunk of the file */
nmax = FBLOCK_SIZE;
bufp = fp->data;
n = read(fd, bufp, nmax);
while (n > 0) {
/* if we didn't read in all we wanted, update the pointers and try to
* fill the current buffer.
*/
fp->hdr.nchars += n;
tchars += n;
if (fp->hdr.nchars < FBLOCK_SIZE) {
nmax -= n;
bufp += n;
} else {
/* filled the current buffer. Get a new one. */
tfp = fp;
fp = (FBLOCK *)malloc(sizeof(char) * 256);
fp->hdr.nxt = NULL;
fp->hdr.nchars = 0;
tfp->hdr.nxt = fp;
nmax = FBLOCK_SIZE;
bufp = fp->data;
}
/* read in the next chunk of the file */
n = read(fd, bufp, nmax);
}
close(fd);
reserved = open("/dev/null", O_RDWR);
if (fp->hdr.nchars == 0) {
free(fp);
if (tfp == NULL)
*cp = NULL;
else
tfp->hdr.nxt = NULL;
}
return tchars;
}
void fcache_load(player)
dbref player;
{
int conn, motd, wiz, new, reg, quit, down, full;
conn = fcache_read(&options.connect_fcache, options.connect_file);
motd = fcache_read(&options.motd_fcache, options.motd_file);
wiz = fcache_read(&options.wizmotd_fcache, options.wizmotd_file);
new = fcache_read(&options.newuser_fcache, options.newuser_file);
reg = fcache_read(&options.register_fcache, options.register_file);
quit = fcache_read(&options.quit_fcache, options.quit_file);
down = fcache_read(&options.down_fcache, options.down_file);
full = fcache_read(&options.full_fcache, options.full_file);
if (player != NOTHING) {
notify(player,
tprintf("File sizes: NewUser...%d Connect...%d Motd...%d Wizmotd...%d Quit...%d Register...%d Down...%d Full...%d",
new, conn, motd, wiz, quit, reg, down, full));
}
}
void fcache_init()
{
options.connect_fcache = NULL;
options.motd_fcache = NULL;
options.wizmotd_fcache = NULL;
options.newuser_fcache = NULL;
options.register_fcache = NULL;
options.quit_fcache = NULL;
options.down_fcache = NULL;
options.full_fcache = NULL;
fcache_load(NOTHING);
}
void logout_sock(d)
struct descriptor_data *d;
{
if (d->connected) {
fcache_dump(d, options.quit_fcache);
do_log(LT_CONN, 0, 0, "[%d/%s] Logout by %s(#%d) <Connection not dropped>",
d->descriptor, d->addr, Name(d->player), d->player);
fflush(connlog_fp);
announce_disconnect(d->player);
#ifdef LOGIN_LIMIT
login_number--;
if (!under_limit && (login_number < MAX_LOGINS)) {
under_limit = 1;
do_log(LT_CONN, 0, 0,
"Below maximum player limit of %d. Logins enabled.",
MAX_LOGINS);
}
#endif /* LOGIN_LIMIT */
} else {
do_log(LT_CONN, 0, 0,
"[%d/%s] Logout, never connected. <Connection not dropped>",
d->descriptor, d->addr);
}
process_output(d); /* flush our old output */
/* pretend we have a new connection */
d->connected = 0;
d->output_prefix = 0;
d->output_suffix = 0;
d->output_size = 0;
d->output.head = 0;
d->player = 0;
d->output.tail = &d->output.head;
d->input.head = 0;
d->input.tail = &d->input.head;
d->raw_input = 0;
d->raw_input_at = 0;
d->quota = COMMAND_BURST_SIZE;
d->last_time = 0;
d->cmds = 0;
d->hide = 0;
#ifdef AT_DOING
d->doing[0] = '\0';
#endif /* AT_DOING */
welcome_user(d);
}
void shutdownsock(d)
struct descriptor_data *d;
{
if (d->connected) {
fcache_dump(d, options.quit_fcache);
do_log(LT_CONN, 0, 0, "[%d/%s] Logout by %s(#%d)",
d->descriptor, d->addr, Name(d->player), d->player);
fflush(connlog_fp);
announce_disconnect(d->player);
#ifdef LOGIN_LIMIT
login_number--;
if (!under_limit && (login_number < MAX_LOGINS)) {
under_limit = 1;
do_log(LT_CONN, 0, 0,
"Below maximum player limit of %d. Logins enabled.",
MAX_LOGINS);
}
#endif /* LOGIN_LIMIT */
} else {
do_log(LT_CONN, 0, 0, "[%d/%s] Connection closed, never connected.",
d->descriptor, d->addr);
}
process_output(d);
clearstrings(d);
shutdown(d->descriptor, 2);
close(d->descriptor);
freeqs(d);
*d->prev = d->next;
if (d->next)
d->next->prev = d->prev;
free((void *) d);
#ifdef MEM_CHECK
del_check("descriptor");
#endif
ndescriptors--;
}
struct descriptor_data *initializesock(s, a, addr)
int s;
struct sockaddr_in *a;
char *addr;
{
struct descriptor_data *d;
ndescriptors++;
d = (struct descriptor_data *) malloc(sizeof(struct descriptor_data));
if(!d)
panic("Out of memory.");
#ifdef MEM_CHECK
add_check("descriptor");
#endif
d->descriptor = s;
d->connected = 0;
make_nonblocking(s);
d->output_prefix = 0;
d->output_suffix = 0;
d->output_size = 0;
d->output.head = 0;
d->player = 0;
d->output.tail = &d->output.head;
d->input.head = 0;
d->input.tail = &d->input.head;
d->raw_input = 0;
d->raw_input_at = 0;
d->quota = COMMAND_BURST_SIZE;
d->last_time = 0;
d->cmds = 0;
d->hide = 0;
#ifdef AT_DOING
d->doing[0] = '\0';
#endif
strncpy(d->addr, addr, 50);
d->address = *a; /* added 5/3/90 SCG */
if (descriptor_list)
descriptor_list->prev = &d->next;
d->next = descriptor_list;
d->prev = &descriptor_list;
descriptor_list = d;
welcome_user(d);
return d;
}
int make_socket(port)
int port;
{
int s;
struct sockaddr_in server;
int opt;
s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) {
perror("creating stream socket");
exit(3);
}
opt = 1;
if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
(char *) &opt, sizeof(opt)) < 0) {
perror("setsockopt");
exit(1);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(port);
if (bind(s, (struct sockaddr *) & server, sizeof(server))) {
perror("binding stream socket");
close(s);
exit(4);
}
listen(s, 5);
return s;
}
struct text_block *make_text_block(s, n)
const char *s;
int n;
{
struct text_block *p;
p = (struct text_block *) malloc(sizeof(struct text_block));
if(!p)
panic("Out of memory");
p->buf = (char *) malloc(sizeof(char) * n);
if(!p->buf)
panic("Out of memory");
#ifdef MEM_CHECK
add_check("text_block");
add_check("text_block_buff");
#endif
bcopy(s, p->buf, n);
p->nchars = n;
p->start = p->buf;
p->nxt = 0;
return p;
}
void free_text_block(t)
struct text_block *t;
{
if (t) {
if (t->buf)
free((void *) t->buf);
free((void *) t);
}
#ifdef MEM_CHECK
del_check("text_block");
del_check("text_block_buff");
#endif
}
void add_to_queue(q, b, n)
struct text_queue *q;
const char *b;
int n;
{
struct text_block *p;
if (n == 0)
return;
p = make_text_block(b, n);
p->nxt = 0;
*q->tail = p;
q->tail = &p->nxt;
}
int flush_queue(q, n)
struct text_queue *q;
int n;
{
struct text_block *p;
int really_flushed = 0;
n += strlen(flushed_message);
while (n > 0 && (p = q->head)) {
n -= p->nchars;
really_flushed += p->nchars;
q->head = p->nxt;
#ifdef DEBUG
fprintf(stderr, "free_text_block(0x%x) at 1.\n", p);
#endif /* DEBUG */
free_text_block(p);
}
p = make_text_block(flushed_message, strlen(flushed_message));
p->nxt = q->head;
q->head = p;
if (!p->nxt)
q->tail = &p->nxt;
really_flushed -= p->nchars;
return really_flushed;
}
int queue_write(d, b, n)
struct descriptor_data *d;
const char *b;
int n;
{
int space;
space = MAX_OUTPUT - d->output_size - n;
if (space < 0)
d->output_size -= flush_queue(&d->output, -space);
add_to_queue(&d->output, b, n);
d->output_size += n;
return n;
}
int queue_string(d, s)
struct descriptor_data *d;
const char *s;
{
return queue_write(d, s, strlen(s));
}
int process_output(d)
struct descriptor_data *d;
{
struct text_block **qp, *cur;
int cnt;
for (qp = &d->output.head; ((cur = *qp) != NULL); ) {
cnt = write(d->descriptor, cur->start, cur->nchars);
if (cnt < 0) {
if (errno == EWOULDBLOCK)
return 1;
return 0;
}
d->output_size -= cnt;
if (cnt == cur->nchars) {
if (!cur->nxt)
d->output.tail = qp;
*qp = cur->nxt;
#ifdef DEBUG
fprintf(stderr, "free_text_block(0x%x) at 2.\n", cur);
#endif /* DEBUG */
free_text_block(cur);
continue; /* do not adv ptr */
}
cur->nchars -= cnt;
cur->start += cnt;
break;
}
return 1;
}
void make_nonblocking(s)
int s;
{
if (fcntl(s, F_SETFL, O_NDELAY) == -1) {
perror("make_nonblocking: fcntl");
panic("O_NDELAY fcntl failed");
}
}
void freeqs(d)
struct descriptor_data *d;
{
struct text_block *cur, *next;
cur = d->output.head;
while (cur) {
next = cur->nxt;
#ifdef DEBUG
fprintf(stderr, "free_text_block(0x%x) at 3.\n", cur);
#endif /* DEBUG */
free_text_block(cur);
cur = next;
}
d->output.head = 0;
d->output.tail = &d->output.head;
cur = d->input.head;
while (cur) {
next = cur->nxt;
#ifdef DEBUG
fprintf(stderr, "free_text_block(0x%x) at 4.\n", cur);
#endif /* DEBUG */
free_text_block(cur);
cur = next;
}
d->input.head = 0;
d->input.tail = &d->input.head;
if (d->raw_input) {
free((void *) d->raw_input);
#ifdef MEM_CHECK
del_check("descriptor_raw_input");
#endif
}
d->raw_input = 0;
d->raw_input_at = 0;
}
void welcome_user(d)
struct descriptor_data *d;
{
fcache_dump(d, options.connect_fcache);
}
#ifdef NEVER
void spew_message(d, filename)
struct descriptor_data *d;
char *filename;
{
int n, fd;
char buf[512];
close(reserved);
if ((fd = open(filename, O_RDONLY)) != -1) {
while ((n = read(fd, buf, 512)) > 0)
queue_write(d, buf, n);
close(fd);
queue_write(d, "\n", 1);
}
reserved = open("/dev/null", O_RDWR);
}
#endif
void do_new_spitfile(player, arg1, index_file, text_file)
dbref player;
char *arg1;
char *index_file;
char *text_file;
{
int help_found;
help_indx entry;
FILE *fp;
char *p, line[LINE_SIZE + 1];
if (*arg1 == '\0')
arg1 = (char *) "help";
if ((fp = fopen(index_file, "r")) == NULL) {
notify(player, "Sorry, that function is temporarily unavailable.");
do_log(LT_ERR, 0, 0, "Can't open index file %s for reading", index_file);
return;
}
while ((help_found = fread(&entry, sizeof(help_indx), 1, fp)) == 1)
if (string_prefix(entry.topic, arg1))
break;
fclose(fp);
if (!help_found) {
notify(player, tprintf("No entry for '%s'.", arg1));
return;
}
if ((fp = fopen(text_file, "r")) == NULL) {
notify(player, "Sorry, that function is temporarily unavailable.");
do_log(LT_ERR, 0, 0, "Can't open text file %s for reading", text_file);
return;
}
if (fseek(fp, entry.pos, 0) < 0L) {
notify(player, "Sorry, that function is temporarily unavailable.");
do_log(LT_ERR, 0, 0, "Seek error in file %s\n", text_file);
return;
}
for (;;) {
if (fgets(line, LINE_SIZE, fp) == NULL)
break;
if (line[0] == '&')
break;
for (p = line; *p != '\0'; p++)
if (*p == '\n')
*p = '\0';
notify(player, line);
}
fclose(fp);
}
char *strsave(s)
const char *s;
{
char *p;
p = (char *) malloc(sizeof(char) * (strlen(s)+1));
if(!p)
panic("Out of memory");
#ifdef MEM_CHECK
add_check("userstring");
#endif
if (p)
strcpy(p, s);
return p;
}
void save_command(d, command)
struct descriptor_data *d;
const char *command;
{
add_to_queue(&d->input, command, strlen(command) + 1);
}
int process_input(d)
struct descriptor_data *d;
{
int got;
char *p, *pend, *q, *qend;
char tbuf1[BUFFER_LEN];
got = read(d->descriptor, tbuf1, sizeof tbuf1);
if (got <= 0)
return 0;
if (!d->raw_input) {
d->raw_input = (char *) malloc(sizeof(char) * MAX_COMMAND_LEN);
if(!d->raw_input)
panic("Out of memory");
#ifdef MEM_CHECK
add_check("descriptor_raw_input");
#endif
d->raw_input_at = d->raw_input;
}
p = d->raw_input_at;
pend = d->raw_input + MAX_COMMAND_LEN - 1;
for (q = tbuf1, qend = tbuf1 + got; q < qend; q++) {
if (*q == '\n') {
*p = '\0';
if (p > d->raw_input)
save_command(d, d->raw_input);
p = d->raw_input;
} else if (p < pend && isascii(*q) && isprint(*q)) {
*p++ = *q;
}
}
if (p > d->raw_input) {
d->raw_input_at = p;
} else {
free((void *) d->raw_input);
#ifdef MEM_CHECK
del_check("descriptor_raw_input");
#endif
d->raw_input = 0;
d->raw_input_at = 0;
}
return 1;
}
void set_userstring(userstring, command)
char **userstring;
const char *command;
{
if (*userstring) {
free((void *) *userstring);
#ifdef MEM_CHECK
del_check("userstring");
#endif
*userstring = 0;
}
while (*command && isascii(*command) && isspace(*command))
command++;
if (*command)
*userstring = strsave(command);
}
void process_commands()
{
int nprocessed;
struct descriptor_data *d, *dnext;
struct text_block *t;
int retval;
do {
nprocessed = 0;
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
if (d->quota > 0 && (t = d->input.head)) {
d->quota--;
nprocessed++;
retval = do_command(d, t->start);
if (retval == 0) {
shutdownsock(d);
} else if (retval == -1) {
logout_sock(d);
} else {
d->input.head = t->nxt;
if (!d->input.head)
d->input.tail = &d->input.head;
if (t) {
#ifdef DEBUG
fprintf(stderr, "free_text_block(0x%x) at 5.\n", t);
#endif /* DEBUG */
free_text_block(t);
}
}
}
}
} while (nprocessed > 0);
}
int do_command(d, command)
struct descriptor_data *d;
char *command;
{
depth = 0;
(d->cmds)++;
if (!strcmp(command, QUIT_COMMAND)) {
return 0;
} else if (!strcmp(command, LOGOUT_COMMAND)) {
return -1;
} else if (!strncmp(command, WHO_COMMAND, strlen(WHO_COMMAND))) {
if (d->output_prefix) {
queue_string(d, d->output_prefix);
queue_write(d, "\n", 1);
}
dump_users(d,command+strlen(WHO_COMMAND),0);
if (d->output_suffix) {
queue_string(d, d->output_suffix);
queue_write(d, "\n", 1);
}
#ifdef AT_DOING
} else if (!strncmp(command, DOING_COMMAND, strlen(DOING_COMMAND))) {
if (d->output_prefix) {
queue_string(d, d->output_prefix);
queue_write(d, "\n", 1);
}
dump_users(d,command+strlen(DOING_COMMAND),1);
if (d->output_suffix) {
queue_string(d, d->output_suffix);
queue_write(d, "\n", 1);
}
#endif
} else if (!strncmp(command, PREFIX_COMMAND, strlen(PREFIX_COMMAND))) {
set_userstring(&d->output_prefix, command + strlen(PREFIX_COMMAND));
} else if (!strncmp(command, SUFFIX_COMMAND, strlen(SUFFIX_COMMAND))) {
set_userstring(&d->output_suffix, command + strlen(SUFFIX_COMMAND));
#ifdef RWHO_SEND
#ifdef FULL_RWHO
} else if (!strcmp(command, RWHO_COMMAND)) {
dump_rusers(d);
#endif
#endif
} else {
if (d->connected) {
if (d->output_prefix) {
queue_string(d, d->output_prefix);
queue_write(d, "\n", 1);
}
cplr = d->player;
strcpy(ccom, command);
process_command(d->player, command, d->player, 1);
if (d->output_suffix) {
queue_string(d, d->output_suffix);
queue_write(d, "\n", 1);
}
} else {
if (!check_connect(d, command))
return 0;
}
}
return 1;
}
static int dump_messages(d, player, new)
DESC *d;
dbref player;
int new; /* 0 if connect, 1 if create */
{
d->connected = 1;
d->connected_at = time((time_t *) 0);
d->player = player;
#ifdef AT_DOING
d->doing[0] = '\0';
#endif
#ifdef LOGIN_LIMIT
/* check for exceeding max player limit */
login_number++;
if (under_limit && (login_number > MAX_LOGINS)) {
under_limit = 0;
fprintf(connlog_fp,
"Limit of %d players reached. Logins disabled.\n",
MAX_LOGINS);
fflush(connlog_fp);
}
#endif /* LOGIN_LIMIT */
/* give players a message on connection */
if (!options.login_allow || !under_limit) {
if (!options.login_allow) {
fcache_dump(d, options.down_fcache);
raw_notify(player, asterisk_line);
if (cf_downmotd_msg && *cf_downmotd_msg)
raw_notify(player, cf_downmotd_msg);
}
#ifdef LOGIN_LIMIT
else if (!under_limit) {
fcache_dump(d, options.full_fcache);
raw_notify(player, asterisk_line);
if (cf_fullmotd_msg && *cf_fullmotd_msg)
raw_notify(player, cf_fullmotd_msg);
}
#endif /* LOGIN_LIMIT */
if (!Can_Login(player)) {
raw_notify(player, asterisk_line);
/* even though the connection has been refused, we still want
* to update the Last info on the player.
*/
check_last(player, d->addr);
return 0;
} else
raw_notify(player, asterisk_line);
}
/* give permanent text messages */
if (new)
fcache_dump(d, options.newuser_fcache);
fcache_dump(d, options.motd_fcache);
if (Hasprivs(player))
fcache_dump(d, options.wizmotd_fcache);
announce_connect(player); /* broadcast connect message */
check_last(player, d->addr); /* set Last, Lastsite, give paycheck */
#ifdef USE_MAILER
if (!new)
check_mail(player, 0);
#endif
do_look_around(player);
if (Haven(player)) {
notify(player, "Your HAVEN flag is set. You cannot receive pages.");
}
return 1;
}
int check_connect(d, msg)
struct descriptor_data *d;
const char *msg;
{
char command[MAX_COMMAND_LEN];
char user[MAX_COMMAND_LEN];
char password[MAX_COMMAND_LEN];
dbref player;
parse_connect(msg, command, user, password);
if (!strncmp(command, "co", 2)) {
if ((player = connect_player(user, password)) == NOTHING) {
queue_string(d, connect_fail);
do_log(LT_CONN, 0, 0, "[%d/%s] Failed connect to '%s'.",
d->descriptor, d->addr, user);
} else {
do_log(LT_CONN, 0, 0, "[%d/%s] Connected to %s(#%d) in %s(#%d)",
d->descriptor, d->addr, Name(player), player,
Name(Location(player)), Location(player));
if ((dump_messages(d, player, 0)) == 0)
return 0;
}
} else if (!strncmp(command, "cr", 2)) {
#ifdef LOCKOUT
if (forbidden_site(0, d->addr)) {
fcache_dump(d, options.register_fcache);
do_log(LT_CONN, 0, 0, "[%d/%s] Refused create for '%s'.",
d->descriptor, d->addr, user);
fflush(connlog_fp);
return 0;
}
#else
#ifdef WCREAT
fcache_dump(d, options.register_fcache);
return 1;
#endif /* WCREAT */
#endif /* LOCKOUT */
if ((player = create_player(user, password, d->addr)) == NOTHING) {
queue_string(d, create_fail);
do_log(LT_CONN, 0, 0, "[%d/%s] Failed create for '%s'.",
d->descriptor, d->addr, user);
} else {
do_log(LT_CONN, 0, 0, "[%d/%s] Created %s(#%d)",
d->descriptor, d->addr, Name(player), player);
if ((dump_messages(d, player, 1)) == 0)
return 0;
} /* successful player creation */
} else {
/* invalid command, just repeat login screen */
welcome_user(d);
}
fflush(connlog_fp);
return 1;
}
void parse_connect(msg, command, user, pass)
const char *msg;
char *command;
char *user;
char *pass;
{
char *p;
while (*msg && isascii(*msg) && isspace(*msg))
msg++;
p = command;
while (*msg && isascii(*msg) && !isspace(*msg))
*p++ = *msg++;
*p = '\0';
while (*msg && isascii(*msg) && isspace(*msg))
msg++;
p = user;
while (*msg && isascii(*msg) && !isspace(*msg))
*p++ = *msg++;
*p = '\0';
while (*msg && isascii(*msg) && isspace(*msg))
msg++;
p = pass;
while (*msg && isascii(*msg) && !isspace(*msg))
*p++ = *msg++;
*p = '\0';
}
void close_sockets()
{
struct descriptor_data *d, *dnext;
#ifdef RWHO_SEND
rwhocli_shutdown();
#endif
for (d = descriptor_list; d; d = dnext) {
dnext = d->next;
write(d->descriptor, shutdown_message, strlen(shutdown_message));
if (shutdown(d->descriptor, 2) < 0)
perror("shutdown");
close(d->descriptor);
}
}
void emergency_shutdown()
{
close_sockets();
}
void boot_off(player)
dbref player;
{
struct descriptor_data *d;
for (d = descriptor_list; d; d = d->next) {
if (d->connected && (d->player == player)) {
shutdownsock(d);
return;
}
}
}
void boot_desc(port)
int port;
{
struct descriptor_data *d;
for (d = descriptor_list; (d); d = d->next) {
if (d->descriptor == port) {
shutdownsock(d);
return;
}
}
}
dbref find_player_by_desc(port)
int port;
{
/* given a descriptor, find the matching player dbref */
struct descriptor_data *d;
for (d = descriptor_list; (d); d = d->next) {
if (d->connected && (d->descriptor == port)) {
return d->player;
}
}
/* didn't find anything */
return NOTHING;
}
int bailout(sig, code, scp)
int sig;
int code;
struct sigcontext *scp;
{
char tbuf1[BUFFER_LEN];
sprintf(tbuf1, "BAILOUT: caught signal %d code %d", sig, code);
panic(tbuf1);
_exit(7);
return 0;
}
void dump_users(call_by, match, doing)
struct descriptor_data *call_by;
char *match;
int doing; /* 0 if normal WHO, 1 if DOING */
{
struct descriptor_data *d;
int count = 0;
time_t now;
char tbuf1[BUFFER_LEN];
char tbuf2[BUFFER_LEN];
if(call_by->player < 0 || call_by->player >= db_top) {
do_log(LT_ERR, 0, 0, "Bogus caller #%d of dump_users", call_by->player);
return;
}
while(*match && *match == ' ') match++;
now = time((time_t *) 0);
/* If a wizard/royal types "DOING" it gives him the normal player WHO,
* BUT flags are not shown. Wizard/royal WHO does not show @doings.
*/
if ((doing) || !Priv_Who(call_by->player)) {
#ifdef AT_DOING
if (poll[0] == '\0')
strcpy(poll, "Doing");
sprintf(tbuf2, "Player Name On For Idle %s\n", poll);
queue_string(call_by, tbuf2);
#else
queue_string(call_by, "Player Name On For Idle\n");
#endif
}
else {
queue_string(call_by,
"Player Name Room # On For Idle Cmds Des Host\n");
}
for (d = descriptor_list; d; d = d->next) {
if (d->connected) {
if(d->player < 0 || d->player >= db_top) continue;
if(!Hidden(d) || Priv_Who(call_by->player)) ++count;
if (match && !(string_prefix(Name(d->player), match)))
continue;
if (call_by->connected && !(doing) && Priv_Who(call_by->player)) {
sprintf(tbuf1, "%-16s %5d %9s %5s %4d %3d %s",
Name(d->player),
Location(d->player),
time_format_1(now - d->connected_at),
time_format_2(now - d->last_time),
d->cmds,
d->descriptor,
d->addr);
if(Hidden(d))
sprintf(tbuf1+strlen(tbuf1)," (Dark)");
} else {
if(!Hidden(d) || (Priv_Who(call_by->player) && (doing))) {
#ifdef AT_DOING
sprintf(tbuf1, "%-16s %10s %4s %s",
#else
sprintf(tbuf1, "%-16s %10s %4s",
#endif
Name(d->player),
time_format_1(now - d->connected_at),
time_format_2(now - d->last_time)
#ifdef AT_DOING
, d->doing
#endif
);
}
}
if(!Hidden(d) || Priv_Who(call_by->player)) {
queue_string(call_by, tbuf1);
queue_write(call_by, "\n", 1);
}
}
}
sprintf(tbuf1, "There are %d players connected.\n", count);
queue_string(call_by, tbuf1);
}
const char *time_format_1(dt)
long dt;
{
register struct tm *delta;
static char buf[64];
if (dt < 0)
dt = 0;
delta = gmtime((time_t *) &dt);
if (delta->tm_yday > 0) {
sprintf(buf, "%dd %02d:%02d",
/* sprintf(buf, "%d:%02d:%02d", */
delta->tm_yday, delta->tm_hour, delta->tm_min);
} else {
sprintf(buf, "%02d:%02d",
delta->tm_hour, delta->tm_min);
}
return buf;
}
const char *time_format_2(dt)
long dt;
{
register struct tm *delta;
static char buf[64];
if (dt < 0)
dt = 0;
delta = gmtime((time_t *)&dt);
if (delta->tm_yday > 0) {
sprintf(buf, "%dd", delta->tm_yday);
} else if (delta->tm_hour > 0) {
sprintf(buf, "%dh", delta->tm_hour);
} else if (delta->tm_min > 0) {
sprintf(buf, "%dm", delta->tm_min);
} else {
sprintf(buf, "%ds", delta->tm_sec);
}
return buf;
}
void announce_connect(player)
dbref player;
{
dbref loc;
ATTR *temp;
char tbuf1[BUFFER_LEN];
dbref zone;
dbref obj;
char *s;
DESC *d;
int num = 0;
int hidden;
#if (CHAT_SYSTEM >= 2)
int b, mask, chan;
#endif
Toggles(player) |= PLAYER_CONNECT;
hidden = Can_Hide(player) && (Flags(player) & DARK);
/* send out RWHO stuff. We're going to use tbuf1 in a moment again */
#ifdef RWHO_SEND
sprintf(tbuf1,"%d@%s", player, MUDNAME);
rwhocli_userlogin(tbuf1, Name(player), time((time_t *) 0));
#endif
/* check to see if this is a reconnect and also set DARK status */
DESC_ITER_CONN(d) {
if (d->player == player) {
num++;
if (hidden)
d->hide = 1;
}
}
if (num > 1)
sprintf(tbuf1, "%s has reconnected.", Name(player));
else
sprintf(tbuf1, "%s has connected.", Name(player));
/* send out messages */
if (Suspect(player))
raw_broadcast(WIZARD, "Broadcast: Suspect %s", tbuf1);
toggle_broadcast(PLAYER_MONITOR, "GAME: %s", tbuf1);
#if (CHAT_SYSTEM >= 2)
/* tell players on a channel when someone connects */
mask = 1;
chan = db[player].channels;
/* Dark players only show up on privileged channels */
if (!Dark(player)) {
for (b = 1; b <= 32; b++) {
if (chan & mask)
channel_broadcast(mask, "<%s> %s", channel_name(mask), tbuf1);
mask <<= 1;
}
} else {
for (b = 1; b <= 32; b++) {
if ((chan & mask) && (ChanPrivs(mask) != CHP_PUBLIC))
channel_broadcast(mask, "<%s> %s", channel_name(mask), tbuf1);
mask <<= 1;
}
}
#endif /* CHAT_SYSTEM */
if ((loc = getloc(player)) == NOTHING) {
notify(player,"You are nowhere!");
return;
}
speaker = player;
raw_notify(player, asterisk_line);
if(cf_motd_msg && *cf_motd_msg)
raw_notify(player, cf_motd_msg);
raw_notify(player, " ");
if(Hasprivs(player) && cf_wizmotd_msg && *cf_wizmotd_msg)
raw_notify(player, cf_wizmotd_msg);
raw_notify(player, asterisk_line);
notify_except(db[player].contents, player, tbuf1);
/* added to allow player's inventory to hear a player connect */
if(!Dark(player))
notify_except(db[loc].contents, player, tbuf1);
/* do the person's personal connect action */
temp = atr_get(player, "ACONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(player, s, player);
free(s);
}
#ifdef GLOBAL_CONNECTS
/* do the zone of the player's location's possible aconnect */
if ((zone = getzone(loc)) != NOTHING) {
switch (Typeof(zone)) {
case TYPE_THING:
temp = atr_get(zone, "ACONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(zone, s, player);
free(s);
}
break;
case TYPE_ROOM:
/* check every object in the room for a connect action */
DOLIST(obj, db[zone].contents) {
temp = atr_get(obj, "ACONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(obj, s, player);
free(s);
}
}
break;
default:
do_log(LT_ERR, 0, 0, "Invalid zone #%d for %s(#%d) has bad type %d",
zone, Name(player), player, Typeof(zone));
}
}
/* now try the master room */
#ifdef DO_GLOBALS
DOLIST(obj, db[MASTER_ROOM].contents) {
temp = atr_get(obj, "ACONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(obj, s, player);
free(s);
}
}
#endif /* DO_GLOBALS */
#endif /* GLOBAL_CONNECTS */
}
void announce_disconnect(player)
dbref player;
{
dbref loc;
int num;
ATTR *temp;
struct descriptor_data *d;
char tbuf1[BUFFER_LEN];
dbref zone, obj;
char *s, *p;
time_t tt;
#if (CHAT_SYSTEM >= 2)
int b, mask, chan;
#endif
tt = time((time_t *) 0);
p = ctime(&tt);
p[strlen(p) - 1] = 0;
if ((loc = getloc(player)) == NOTHING)
return;
speaker = player;
for (num = 0, d = descriptor_list; d; d = d->next)
if (d->connected && (d->player == player))
num++;
if (num < 2) {
#ifdef RWHO_SEND
sprintf(tbuf1, "%d@%s", player, MUDNAME);
rwhocli_userlogout(tbuf1);
#endif
sprintf(tbuf1, "%s has disconnected.", Name(player));
if(!Dark(player))
notify_except(db[loc].contents, player, tbuf1);
/* notify contents */
notify_except(db[player].contents,player, tbuf1);
temp = atr_get(player, "ADISCONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(player, s, player);
free(s);
}
#ifdef GLOBAL_CONNECTS
/* do the zone of the player's location's possible adisconnect */
if ((zone = getzone(loc)) != NOTHING) {
switch (Typeof(zone)) {
case TYPE_THING:
temp = atr_get(zone, "ADISCONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(zone, s, player);
free(s);
}
break;
case TYPE_ROOM:
/* check every object in the room for a connect action */
DOLIST(obj, db[zone].contents) {
temp = atr_get(obj, "ADISCONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(obj, s, player);
free(s);
}
}
break;
default:
do_log(LT_ERR, 0, 0, "Invalid zone #%d for %s(#%d) has bad type %d",
zone, Name(player), player, Typeof(zone));
}
}
/* now try the master room */
#ifdef DO_GLOBALS
DOLIST(obj, db[MASTER_ROOM].contents) {
temp = atr_get(obj, "ADISCONNECT");
if (temp) {
s = safe_uncompress(temp->value);
parse_que(obj, s, player);
free(s);
}
}
#endif /* DO_GLOBALS */
#endif /* GLOBAL_CONNECTS */
Toggles(player) &= ~PLAYER_CONNECT;
sprintf(tbuf1, "%s has disconnected.", Name(player));
} else {
/* note: when you partially disconnect, ADISCONNECTS are not executed */
sprintf(tbuf1, "%s has partially disconnected.", Name(player));
if(!Dark(player))
notify_except(db[loc].contents, player, tbuf1);
/* notify contents */
notify_except(db[player].contents,player, tbuf1);
}
/* now print messages */
if (Suspect(player))
raw_broadcast(WIZARD, "Broadcast: Suspect %s", tbuf1);
toggle_broadcast(PLAYER_MONITOR, "GAME: %s", tbuf1);
#if (CHAT_SYSTEM >= 2)
/* tell players on channel that someone's left */
mask = 1;
chan = db[player].channels;
/* Dark players only show up on priv'ed channels */
if (!Dark(player)) {
for (b = 1; b <= 32; b++) {
if (chan & mask)
channel_broadcast(mask, "<%s> %s", channel_name(mask), tbuf1);
mask <<= 1;
}
} else {
for (b = 1; b <= 32; b++) {
if ((chan & mask) && (ChanPrivs(mask) != CHP_PUBLIC))
channel_broadcast(mask, "<%s> %s", channel_name(mask), tbuf1);
mask <<= 1;
}
}
#endif /* CHAT_SYSTEM */
}
void do_motd(player, key, message)
dbref player;
int key;
const char *message;
{
if (!Wizard(player) && (key != 3)) {
notify(player,
"You may get 15 minutes of fame and glory in life, but not right now.");
return;
}
switch(key) {
case 1:
strcpy(cf_motd_msg, message);
notify(player, "Motd set.");
break;
case 2:
strcpy(cf_wizmotd_msg, message);
notify(player, "Wizard motd set.");
break;
case 4:
strcpy(cf_downmotd_msg, message);
notify(player, "Down motd set.");
break;
case 5:
strcpy(cf_fullmotd_msg, message);
notify(player, "Full motd set.");
break;
default:
notify(player, tprintf("MOTD: %s", cf_motd_msg));
if (Hasprivs(player)) {
notify(player, tprintf("Wiz MOTD: %s", cf_wizmotd_msg));
notify(player, tprintf("Down MOTD: %s", cf_downmotd_msg));
notify(player, tprintf("Full MOTD: %s", cf_fullmotd_msg));
}
}
}
#ifdef AT_DOING
void do_doing(player, message)
dbref player;
const char *message;
{
char buf[MAX_COMMAND_LEN];
struct descriptor_data *d;
int i;
if (!Connected(player)) {
/* non-connected things have no need for a doing */
notify(player, "Why would you want to do that?");
return;
}
strncpy(buf, message, 39);
/* now smash undesirable characters and truncate */
for (i = 0; i < 40; i++) {
if ((buf[i] == '\r') || (buf[i] == '\n') ||
(buf[i] == '\t') || (buf[i] == '\a'))
buf[i] = ' ';
}
buf[39]='\0';
/* set it */
for (d = descriptor_list; d; d=d->next)
if (d->connected && (d->player == player))
strcpy(d->doing, buf);
if (strlen(message) > 39)
notify(player,
tprintf("Doing set. %d characters lost.", strlen(message) - 39));
else
notify(player, "Doing set.");
}
/* this sets the message which replaces "Doing" */
void do_poll(player, message)
dbref player;
const char *message;
{
if (!Change_Poll(player)) {
notify(player, "Who do you think you are, Gallup?");
return;
}
strncpy(poll, message, 39);
if (strlen(message) > 39)
notify(player,
tprintf("Poll set. %d characters lost.", strlen(message) - 39));
else
notify(player, "Poll set.");
do_log(LT_WIZ, player, NOTHING, "Poll Set to '%s'.", poll);
fflush(wizlog_fp);
}
#endif /* AT_DOING */
#ifdef RWHO_SEND
#ifdef FULL_RWHO
void dump_rusers(call_by)
struct descriptor_data *call_by;
{
struct sockaddr_in addr;
struct hostent *hp;
char *p;
int fd;
int red;
char *srv = NULL;
int portnum = RWHOPORT;
char tbuf1[BUFFER_LEN];
p = srv = (char *)RWHOSERV;
while (*p != '\0' && (*p == '.' || isdigit(*p)))
p++;
if(*p != '\0') {
if((hp = gethostbyname(srv)) == (struct hostent *)0) {
do_log(LT_ERR, 0, 0, "Unknown RWHO host %s", srv);
queue_string(call_by,"Error in connecting to the RWHO server.\n");
return;
}
(void)bcopy(hp->h_addr,(char *)&addr.sin_addr,hp->h_length);
} else {
unsigned long f;
if((f = inet_addr(srv)) == -1L) {
do_log(LT_ERR, 0, 0, "Unknown RWHO host %s", srv);
queue_string(call_by,"Error in connecting to the RWHO server.\n");
return;
}
(void)bcopy((char *)&f,(char *)&addr.sin_addr,sizeof(f));
}
addr.sin_port = htons(portnum);
addr.sin_family = AF_INET;
if((fd = socket(AF_INET,SOCK_STREAM,0)) < 0) {
queue_string(call_by, "Socket error in connecting to rwhod. sorry.\n");
return;
}
if(connect(fd,&addr,sizeof(addr)) < 0) {
queue_string(call_by, "Connect error in connecting to rwhod. sorry.\n");
return;
}
while((red = read(fd, tbuf1, sizeof(tbuf1))) > 0)
queue_write(call_by, tbuf1, red);
close(fd);
}
#endif /*FULL_RWHO*/
void rwho_update()
{
struct descriptor_data *d;
char tbuf1[BUFFER_LEN];
rwhocli_pingalive();
for (d = descriptor_list; d; d= d->next) {
if(d->connected && !Hidden(d)) {
sprintf(tbuf1, "%d@%s", d->player, MUDNAME);
rwhocli_userlogin(tbuf1, Name(d->player), d->connected_at);
}
}
}
#endif /* RWHO_SEND */
#ifdef LOCKOUT
int quick_wild(s, d)
char *s;
char *d;
{
switch(*s) {
case '?':
return(wild(s+1, (*d) ? d+1 : d));
case '*':
return(wild(s+1, d) || ((*d) ? wild(s,d+1) : 0));
default:
return((UPCASE(*s) != UPCASE(*d)) ? 0 : ((*s) ? wild(s+1,d+1) : 1));
}
}
int site_match(site, match)
const char *site, *match;
{
if (*match == '\0')
return 0;
while(match && *match) {
switch (*match) {
case '*':
match++;
while ((*site) && (*site != '.') && (*site != '\0'))
site++;
break;
case '?':
match++;
site++;
break;
default:
if (UPCASE(*match) != UPCASE(*site))
return 0;
site++;
match++;
}
}
return 1;
}
int forbidden_site(flag, hname)
int flag; /* 0 for registration, 1 for lockout */
const char *hname;
{
char buf[MAXHOSTNAMELEN], *newlin, *ptr;
FILE *fp;
if (flag)
fp = fopen(LOCKOUT_FILE, "r");
else
fp = fopen(REGISTER_FILE, "r");
while ((fp != NULL) && (!feof(fp))) {
fgets(buf, MAXHOSTNAMELEN, fp);
/* step on the newline */
if ((newlin = (char *) index(buf, '\n')) != NULL) *newlin = '\0';
ptr = buf;
if (site_match(hname, ptr)) {
fclose(fp);
return 1;
}
}
fclose(fp);
return 0;
}
#endif /* LOCKOUT */
#ifdef NEVER
const char *addrout(a)
long a;
{
static char buf[MAXHOSTNAMELEN];
struct hostent *he;
he = gethostbyaddr(&a, sizeof(a), AF_INET);
if (he) {
return he->h_name;
} else {
a = ntohl(a);
sprintf (buf, "%d.%d.%d.%d", (a >> 24) & 0xff, (a >> 16) & 0xff,
(a >> 8) & 0xff, a & 0xff);
return buf;
}
}
#endif
const char *hostname_convert(nums)
struct in_addr nums;
{
/* given an address, convert it to either IP numbers or a hostname */
struct hostent *he;
he = gethostbyaddr((const char *)&nums.s_addr, sizeof(nums.s_addr), AF_INET);
if (he == NULL)
return ((char *)inet_ntoa(nums)); /* IP numbers */
else
return ((char *)he->h_name); /* hostname */
}
dbref short_page(match)
const char *match;
{
/* attempts to match to the partial name of a connected player */
struct descriptor_data *d;
dbref who1 = NOTHING;
int count = 0;
for(d = descriptor_list; d; d = d->next) {
if(d->connected) {
if (match && !string_prefix(Name(d->player), match))
continue;
if (!strcasecmp(Name(d->player), match)) {
count = 1;
who1 = d->player;
break;
}
who1 = d->player;
count++;
}
}
if(count > 1)
return AMBIGUOUS;
else if (count == 0)
return NOTHING;
return who1;
}
/* LWHO() function - really belongs in eval.c but needs stuff declared here */
XFUNCTION(fun_lwho)
{
struct descriptor_data *d;
char tbuf1[SBUF_LEN];
char *bp;
*buff = '\0';
bp = buff;
DESC_ITER_CONN(d) {
if (!Hidden(d) || Priv_Who(privs)) {
if (*buff)
sprintf(tbuf1, " #%d", d->player);
else
sprintf(tbuf1, "#%d", d->player);
safe_str(tbuf1, buff, &bp);
}
}
*bp = '\0';
}
XFUNCTION(fun_idlesecs)
{
/* returns the number of seconds a player has been idle */
time_t now;
struct descriptor_data *d;
dbref target;
now = time((time_t *) 0);
target = lookup_player(args[0]);
if (target == NOTHING) {
init_match(privs, args[0], TYPE_PLAYER);
match_absolute();
match_player();
target = match_result();
}
/* non-connected players return error -1 */
if ((target == NOTHING) || !Connected(target)) {
strcpy(buff, "-1");
return;
}
/* else walk the descriptor list looking for a match */
DESC_ITER_CONN(d) {
if (d->player == target) {
if (!Hidden(d) || Priv_Who(privs))
sprintf(buff, "%d", (now - d->last_time));
else
strcpy(buff, "-1");
return;
}
}
/* if we hit this point we are in trouble */
strcpy(buff, "-1");
do_log(LT_ERR, 0, 0,
"Whoa. idlesecs() can't find player #%d on call by #%d\n",
target, privs);
}
XFUNCTION(fun_conn)
{
/* returns the number of seconds a player has been connected */
time_t now;
struct descriptor_data *d;
dbref target;
now = time((time_t *) 0);
target = lookup_player(args[0]);
if (target == NOTHING) {
init_match(privs, args[0], TYPE_PLAYER);
match_absolute();
match_player();
target = match_result();
}
/* non-connected players and dark wizards return error, -1 */
if ((target == NOTHING) || !Connected(target)) {
strcpy(buff, "-1");
return;
}
/* else walk the descriptor list looking for a match */
DESC_ITER_CONN(d) {
if (d->player == target) {
if (!Hidden(d) || Priv_Who(privs))
sprintf(buff, "%d", (now - d->connected_at));
else
strcpy(buff, "-1");
return;
}
}
/* if we hit this point we are in trouble */
strcpy(buff, "-1");
do_log(LT_ERR, 0, 0, "Whoa. conn() can't find player #%d on call by #%d\n",
target, privs);
}
void hide_player(player, hide)
dbref player;
int hide; /* hide player? */
{
DESC *d;
#ifdef RWHO_SEND
char buf[BUFFER_LEN];
#endif
if (!Connected(player))
return;
if (!Can_Hide(player)) {
notify(player, "Permission denied.");
return;
}
/* change status on WHO */
if (Can_Hide(player)) {
DESC_ITER_CONN(d) {
if (d->player == player)
d->hide = hide;
}
}
/* change status on RWHO if necessary */
#ifdef RWHO_SEND
sprintf(buf, "%d@%s", player, MUDNAME);
if (hide)
rwhocli_userlogout(buf);
else
rwhocli_userlogin(buf, Name(player), time((time_t *)NULL));
#endif
}
#ifdef IDLE_TIMEOUT
void inactivity_check()
{
DESC *d;
register struct tm *idle;
time_t now;
int check, hrs, mns;
check = hrs = mns = 0;
now = time((time_t *) 0);
for (mns = INACTIVITY_LIMIT; mns > 60; mns -= 60, hrs++)
;
DESC_ITER_CONN(d) {
check = (now - d->last_time);
idle = gmtime((time_t *) &check);
if ((idle->tm_hour > hrs) ||
((idle->tm_hour == hrs) && (idle->tm_min >= mns))) {
if (!Can_Idle(d->player)) {
notify(d->player, "\n*** Inactivity timeout ***\n");
do_log(LT_CONN, 0, 0, "[%d/%s] Logout by %s(#%d) <Inactivity Timeout>",
d->descriptor, d->addr, Name(d->player), d->player);
fflush(connlog_fp);
boot_off(d->player);
} else if (Unfind(d->player)) {
if (Can_Hide(d->player)) {
notify(d->player,
"\n*** Inactivity limit reached. You are now DARK. ***\n");
Flags(d->player) |= DARK;
} else {
notify(d->player, "\n*** Inactivity limit reached. ***\n");
}
}
}
}
}
#endif /* IDLE_TIMEOUT */
#if (CHAT_SYSTEM >= 2)
void channel_broadcast(channel, va_alist)
channel_type channel;
va_dcl
{
va_list args;
char *fmt;
char tbuf1[BUFFER_LEN];
DESC *d;
/* Make sure we can write to the channel before doing so */
if (ChanPrivs(channel) == CHP_FORBID)
return;
va_start(args);
fmt = va_arg(args, char *);
(void) vsprintf(tbuf1, fmt, args);
DESC_ITER_CONN(d) {
if ((db[d->player].channels & channel) == channel) {
queue_string(d, tbuf1);
queue_write(d, "\n", 1);
process_output(d);
}
}
}
void do_channel_who(player, chan)
dbref player;
channel_type chan;
{
DESC *d;
char tbuf1[BUFFER_LEN];
tbuf1[0] = '\0';
DESC_ITER_CONN(d) {
if (((db[d->player].channels & chan) == chan) &&
(!Dark(d->player) || Priv_Who(player))) {
if (tbuf1[0] == '\0') /* beginning of list */
sprintf(tbuf1, "%s", Name(d->player));
else if ((strlen(tbuf1) + PLAYER_NAME_LIMIT) < BUFFER_LEN)
sprintf(tbuf1, "%s, %s", tbuf1, Name(d->player));
}
}
if (tbuf1[0] == '\0')
notify(player, "There are no connected players on that channel.");
else {
notify(player, "Connected players on that channel are:");
notify(player, tbuf1);
}
}
#endif /* CHAT_SYSTEM */